/*
 *  Copyright 2019-2020 Fang Jin Biao
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.admin.system.controller;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.admin.system.model.UserModel;
import com.admin.system.service.IDataService;
import com.admin.system.service.IDeptService;
import com.admin.system.service.IRoleService;
import com.admin.system.service.IUserService;
import com.admin.system.service.IVerifyService;
import com.admin.utils.Utils;
import com.baomidou.mybatisplus.core.metadata.IPage;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.zhengjie.annotation.Log;
import me.zhengjie.config.RsaProperties;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.system.domain.vo.UserPassVo;
import me.zhengjie.modules.system.service.dto.RoleSmallDto;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.modules.system.service.dto.UserQueryCriteria;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.RsaUtils;
import me.zhengjie.utils.SecurityUtils;
import me.zhengjie.utils.enums.CodeEnum;

/**
 * @author adyfang
 * @date 2020年5月2日
 */
@Api(tags = "系统：用户管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class AdminUserController {

	private final PasswordEncoder passwordEncoder;

	private final IUserService userService;

	private final IDataService dataService;

	private final IDeptService deptService;

	private final IRoleService roleService;

	private final IVerifyService verificationCodeService;

	@Log("导出用户数据")
	@ApiOperation("导出用户数据")
	@GetMapping(value = "/download")
	@PreAuthorize("@el.check('user:list')")
	public void download(HttpServletResponse response, UserQueryCriteria criteria) throws IOException {
		userService.download(userService.queryAll(criteria), response);
	}

	@SuppressWarnings("rawtypes")
	@Log("查询用户")
	@ApiOperation("查询用户")
	@GetMapping
	@PreAuthorize("@el.check('user:list')")
	public ResponseEntity<Object> getUsers(UserQueryCriteria criteria, Pageable pageable) {
		IPage page = Utils.convertPage(pageable);
		if (!ObjectUtils.isEmpty(criteria.getDeptId())) {
			criteria.getDeptIds().add(criteria.getDeptId());
			criteria.getDeptIds().addAll(
					deptService.getDeptChildren(criteria.getDeptId(), deptService.findByPid(criteria.getDeptId())));
		}
		// 数据权限
		List<Long> dataScopes = dataService.getDeptIds(userService.findById(SecurityUtils.getCurrentUserId()));
		// criteria.getDeptIds() 不为空并且数据权限不为空则取交集
		if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)) {
			// 取交集
			criteria.getDeptIds().retainAll(dataScopes);
			if (!CollectionUtils.isEmpty(criteria.getDeptIds())) {
				return new ResponseEntity<>(userService.queryAll(criteria, page), HttpStatus.OK);
			}
		} else {
			// 否则取并集
			criteria.getDeptIds().addAll(dataScopes);
			return new ResponseEntity<>(userService.queryAll(criteria, page), HttpStatus.OK);
		}
		return new ResponseEntity<>(PageUtil.toPage(null, 0), HttpStatus.OK);
	}

	@Log("新增用户")
	@ApiOperation("新增用户")
	@PostMapping
	@PreAuthorize("@el.check('user:add')")
	public ResponseEntity<Object> create(@Validated @RequestBody UserModel resources) {
		checkLevel(resources);
		// 默认密码 123456
		resources.setPassword(passwordEncoder.encode("123456"));
		userService.create(resources);
		return new ResponseEntity<>(HttpStatus.CREATED);
	}

	@Log("修改用户")
	@ApiOperation("修改用户")
	@PutMapping
	@PreAuthorize("@el.check('user:edit')")
	public ResponseEntity<Object> update(@Validated(UserModel.Update.class) @RequestBody UserModel resources) {
		checkLevel(resources);
		userService.update(resources);
		return new ResponseEntity<>(HttpStatus.NO_CONTENT);
	}

	@Log("修改用户：个人中心")
	@ApiOperation("修改用户：个人中心")
	@PutMapping(value = "center")
	public ResponseEntity<Object> center(@Validated(UserModel.Update.class) @RequestBody UserModel resources) {
		if (!resources.getId().equals(SecurityUtils.getCurrentUserId())) {
			throw new BadRequestException("不能修改他人资料");
		}
		userService.updateCenter(resources);
		return new ResponseEntity<>(HttpStatus.NO_CONTENT);
	}

	@Log("删除用户")
	@ApiOperation("删除用户")
	@DeleteMapping
	@PreAuthorize("@el.check('user:del')")
	public ResponseEntity<Object> delete(@RequestBody Set<Long> ids) {
		for (Long id : ids) {
			Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream()
					.map(RoleSmallDto::getLevel).collect(Collectors.toList()));
			Integer optLevel = Collections.min(
					roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
			if (currentLevel > optLevel) {
				throw new BadRequestException("角色权限不足，不能删除：" + userService.findById(id).getUsername());
			}
		}
		userService.delete(ids);
		return new ResponseEntity<>(HttpStatus.OK);
	}

	@ApiOperation("修改密码")
	@PostMapping(value = "/updatePass")
	public ResponseEntity<Object> updatePass(@RequestBody UserPassVo passVo) throws Exception {
		// 密码解密
		String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, passVo.getOldPass());
		String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, passVo.getNewPass());
		UserDto user = userService.findByName(SecurityUtils.getCurrentUsername());
		if (!passwordEncoder.matches(oldPass, user.getPassword())) {
			throw new BadRequestException("修改失败，旧密码错误");
		}
		if (passwordEncoder.matches(newPass, user.getPassword())) {
			throw new BadRequestException("新密码不能与旧密码相同");
		}
		userService.updatePass(user.getUsername(), passwordEncoder.encode(newPass));
		return new ResponseEntity<>(HttpStatus.OK);
	}

	@ApiOperation("修改头像")
	@PostMapping(value = "/updateAvatar")
	public ResponseEntity<Object> updateAvatar(@RequestParam MultipartFile avatar) {
		return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK);
	}

	@Log("修改邮箱")
	@ApiOperation("修改邮箱")
	@PostMapping(value = "/updateEmail/{code}")
	public ResponseEntity<Object> updateEmail(@PathVariable String code, @RequestBody UserModel user) throws Exception {
		String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, user.getPassword());
		UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername());
		if (!passwordEncoder.matches(password, userDto.getPassword())) {
			throw new BadRequestException("密码错误");
		}
		verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + user.getEmail(), code);
		userService.updateEmail(userDto.getUsername(), user.getEmail());
		return new ResponseEntity<>(HttpStatus.OK);
	}

	/**
	 * 如果当前用户的角色级别低于创建用户的角色级别，则抛出权限不足的错误
	 * 
	 * @param resources /
	 */
	private void checkLevel(UserModel resources) {
		Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream()
				.map(RoleSmallDto::getLevel).collect(Collectors.toList()));
		Integer optLevel = roleService.findByRoles(resources.getRoles());
		if (currentLevel > optLevel) {
			throw new BadRequestException("角色权限不足");
		}
	}
}
